//////////////////////////////////////////////////////////////////////////////
//
//  Created by Philip Mulcahy on 18/06/2012.
//  Copyright (c) 2012 Philip Mulcahy. All rights reserved.
//
//  This file is part of the note-recog library.
//
//  note-recog is free software: you can redistribute it and/or modify
//  it under the terms of version 3 of the GNU Lesser General Public License 
//  as published by the Free Software Foundation.
//
//  note-recog is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.
//
//  You should have received a copy of the GNU General Public License
//  along with note-recog. If not, see <http://www.gnu.org/licenses/>.
//
//////////////////////////////////////////////////////////////////////////////


#import "OptimiserTests.h"
#import "Optimiser.h"

static float oneDimensionalFunc( const Optimiser::single_input& input )
{
    const float x = input.find("x")->second;
    return 10.f - (x*x);
}

@implementation OptimiserTests
	
- (void)testOptimise2DParabola
{
    Optimiser::arg_range xRange("x");
    for( int x = -2; x != 3; ++x )
    {
        xRange.insert(x);
    }
    
    Optimiser::input_ranges inputRanges;
    inputRanges.add(xRange);
    
    const Optimiser optimiser( oneDimensionalFunc, inputRanges );
    Optimiser::input_set optimisedInputs;
    const float optimisedOutput = optimiser.getPeak(&optimisedInputs);
    
    STAssertEqualsWithAccuracy(
                               10.f, 
                               optimisedOutput,
                               0.001,
                               @"wrong optimised inputs");
    
    const size_t optimizedInputCount = optimisedInputs.size();
    
    STAssertEquals(static_cast<int>(optimizedInputCount), 1, @"wrong count");
    
//    const Optimiser::input_set::const_iterator i1 = optimisedInputs.begin();
  
    STAssertEqualsWithAccuracy(
                               0.f, 
                               optimisedInputs
                                    .begin()
                                    ->find("x")
                                    ->second, 
                               0.001,
                               @"wrong peak input found");
    
    std::cout << optimisedInputs;
}

static float threeDimensionalFunc( const Optimiser::single_input& input )
{
    const float x = input.find("x")->second;
    const float y = input.find("y")->second;
    const float z = input.find("z")->second;
    return 10.f - ((x*x) + (y*y) + (z*z) );
}

- (void)testOptimise4DParabola
{
    Optimiser::arg_range xRange("x");
    Optimiser::arg_range yRange("y");
    Optimiser::arg_range zRange("z");
    for( int x = -25; x != 25; x+=5 )
    {
        xRange.insert(x);
        yRange.insert(x);
        zRange.insert(x);
    }
    
    Optimiser::input_ranges inputRanges;
    inputRanges["x"] = xRange;
    inputRanges["y"] = yRange;
    inputRanges["z"] = zRange;
    
    const Optimiser optimiser( threeDimensionalFunc, inputRanges );
    Optimiser::input_set optimisedInputs;
    const float optimisedOutput = optimiser.getPeak(&optimisedInputs);
    
    STAssertEqualsWithAccuracy(
                               10.f, 
                               optimisedOutput,
                               0.001,
                               @"wrong optimised inputs");
    
    const size_t optimizedInputCount = optimisedInputs.size();
    
    STAssertEquals(static_cast<int>(optimizedInputCount), 1, @"wrong count");
    
//    const Optimiser::input_set::const_iterator i1 = optimisedInputs.begin();
    
    STAssertEqualsWithAccuracy(
                               0.f, 
                               optimisedInputs
                               .begin()
                               ->find("x")
                               ->second, 
                               0.001,
                               @"wrong peak x found");
    
    STAssertEqualsWithAccuracy(
                               0.f, 
                               optimisedInputs
                               .begin()
                               ->find("y")
                               ->second, 
                               0.001,
                               @"wrong peak y found");
    
    
    STAssertEqualsWithAccuracy(
                               0.f, 
                               optimisedInputs
                               .begin()
                               ->find("z")
                               ->second, 
                               0.001,
                               @"wrong peak z found");
    
    std::cout << optimisedInputs;
}

@end
